<!DOCTYPE html>
<html>

<head>
    
    <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer">

<meta name="description" content="A new Hugo site.">
<title>
    用Dockerfile，docker-compose编排服务 - dashjay
</title>



<link rel="shortcut icon" href="/sam.ico">








<link rel="stylesheet" href="/css/main.min.4321edce0de245f4b1d32680d89ac669940fe5dec17e1791c721d9a0954987b4.css" integrity="sha256-QyHtzg3iRfSx0yaA2JrGaZQP5d7BfheRxyHZoJVJh7Q=" crossorigin="anonymous" media="screen">





<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Didact+Gothic">

<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="http://dashjay.gitee.io/tn.png"/>

<meta name="twitter:title" content="用Dockerfile，docker-compose编排服务"/>
<meta name="twitter:description" content="有时候交付的时候，你要么在服务器上部署好服务，将服务器交给老板，或者将源代码直接丢给老板，但是，有时候和你和做的人几乎没有协作能力。因此这时候可以使用docker-compose和Dockerfile去将服务编排好，一键即可运行服务。
Dockerfile 1. FROM 指定基础镜像 2. RUN 执行命令  RUN &lt;命令&gt; ，就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。  FROM nginx RUN echo &#39;&lt;h1&gt;Hello, Docker!&lt;/h1&gt;&#39; &gt; /usr/share/nginx/html/index.html   exec 格式： RUN [&ldquo;可执行文件&rdquo;, &ldquo;参数1&rdquo;, &ldquo;参数2&rdquo;]，这更像是函数调用中的格式。
 可以一层一层执行如下，但是每执行一句就会新建一层镜像
 FROM debian:jessie RUN apt-get update RUN apt-get install -y gcc libc6-dev make RUN wget -O redis.tar.gz &#34;http://download.redis.io/releases/redis-3.2.5.tar.gz&#34; RUN mkdir -p /usr/src/redis RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 RUN make -C /usr/src/redis    因此无法不建议写这么多东西在Dockerfile中，一般采用这种写法,减少命令行数 FROM debian:jessie RUN buildDeps=&#39;gcc libc6-dev make&#39; \  &amp;&amp; apt-get update \  &amp;&amp; apt-get install -y $buildDeps \  &amp;&amp; wget -O redis."/>

<meta property="og:title" content="用Dockerfile，docker-compose编排服务" />
<meta property="og:description" content="有时候交付的时候，你要么在服务器上部署好服务，将服务器交给老板，或者将源代码直接丢给老板，但是，有时候和你和做的人几乎没有协作能力。因此这时候可以使用docker-compose和Dockerfile去将服务编排好，一键即可运行服务。
Dockerfile 1. FROM 指定基础镜像 2. RUN 执行命令  RUN &lt;命令&gt; ，就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。  FROM nginx RUN echo &#39;&lt;h1&gt;Hello, Docker!&lt;/h1&gt;&#39; &gt; /usr/share/nginx/html/index.html   exec 格式： RUN [&ldquo;可执行文件&rdquo;, &ldquo;参数1&rdquo;, &ldquo;参数2&rdquo;]，这更像是函数调用中的格式。
 可以一层一层执行如下，但是每执行一句就会新建一层镜像
 FROM debian:jessie RUN apt-get update RUN apt-get install -y gcc libc6-dev make RUN wget -O redis.tar.gz &#34;http://download.redis.io/releases/redis-3.2.5.tar.gz&#34; RUN mkdir -p /usr/src/redis RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 RUN make -C /usr/src/redis    因此无法不建议写这么多东西在Dockerfile中，一般采用这种写法,减少命令行数 FROM debian:jessie RUN buildDeps=&#39;gcc libc6-dev make&#39; \  &amp;&amp; apt-get update \  &amp;&amp; apt-get install -y $buildDeps \  &amp;&amp; wget -O redis." />
<meta property="og:type" content="article" />
<meta property="og:url" content="http://dashjay.gitee.io/posts/dockerfile-docker-compose/" />
<meta property="og:image" content="http://dashjay.gitee.io/tn.png"/>
<meta property="article:published_time" content="2019-07-28T00:00:00+00:00" />
<meta property="article:modified_time" content="2019-07-28T00:00:00+00:00" /><meta property="og:site_name" content="Call me Sam" />


    

    
    
    
    <title>
        
        用Dockerfile，docker-compose编排服务
        
    </title>
</head>

<body>
    
    
    <header class="wrap flex-container">
        <h1>用Dockerfile，docker-compose编排服务</h1>
    </header>
    
    <main class="wrap">
        
<div class="flex-container">
    <aside role="complementary">
        Sun Jul 28, 2019 &#183; 657 words
        <div class="tag-container">
            
        </div>
    </aside>
    <hr />
    <article role="article">
        <p>有时候交付的时候，你要么在服务器上部署好服务，将服务器交给老板，或者将源代码直接丢给老板，但是，有时候和你和做的人几乎没有协作能力。因此这时候可以使用<code>docker-compose</code>和<code>Dockerfile</code>去将服务编排好，一键即可运行服务。</p>
<h1 id="dockerfile">Dockerfile</h1>
<h2 id="1-from-指定基础镜像">1. FROM 指定基础镜像</h2>
<h2 id="2-run-执行命令">2. RUN 执行命令</h2>
<ul>
<li>RUN &lt;命令&gt; ，就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">FROM nginx
RUN echo <span style="color:#e6db74">&#39;&lt;h1&gt;Hello, Docker!&lt;/h1&gt;&#39;</span> &gt; /usr/share/nginx/html/index.html
</code></pre></div><ul>
<li>
<p>exec 格式： RUN [&ldquo;可执行文件&rdquo;, &ldquo;参数1&rdquo;, &ldquo;参数2&rdquo;]，这更像是函数调用中的格式。</p>
<blockquote>
<p>可以一层一层执行如下，但是每执行一句就会新建一层镜像</p>
</blockquote>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">FROM debian:jessie
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN wget -O redis.tar.gz <span style="color:#e6db74">&#34;http://download.redis.io/releases/redis-3.2.5.tar.gz&#34;</span>
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>
RUN make -C /usr/src/redis
</code></pre></div></li>
</ul>
<hr>
<h1 id="因此无法不建议写这么多东西在dockerfile中一般采用这种写法减少命令行数">因此无法不建议写这么多东西在Dockerfile中，一般采用这种写法,减少命令行数</h1>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">FROM debian:jessie
RUN buildDeps<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;gcc libc6-dev make&#39;</span> <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> apt-get update <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> apt-get install -y $buildDeps <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> wget -O redis.tar.gz <span style="color:#e6db74">&#34;http://download.redis.io/releases/redis-3.2.5.tar.gz&#34;</span> <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> mkdir -p /usr/src/redis <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> tar -xzf redis.tar.gz -C /usr/src/redis --strip-components<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span> <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> make -C /usr/src/redis <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> make -C /usr/src/redis install <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> rm -rf /var/lib/apt/lists/* <span style="color:#ae81ff">\
</span></code></pre></div><blockquote>
<p>在撰写 Dockerfile 的时候，要经常提醒自己，这并不是在写 Shell 脚本，而是在定义每一层该如何构建。</p>
</blockquote>
<p>Docker支持注释和换行</p>
<blockquote>
<p>Dockerfile 支持 Shell 类的行尾添加 \ 的命令换行方式，以及行首 # 进行注释的格式。良好的格式，比如换行、缩进、注释等，会让维护、排障更为容易，这是一个比较好的习惯。</p>
</blockquote>
<h2 id="3-运行dockerfile">3. 运行Dockerfile</h2>
<p><code>$docker build -t nginx:v3 .</code></p>
<p>注意最后有个点指定上下文目录</p>
<h2 id="4-镜像构建上下文context">4. 镜像构建上下文（Context）</h2>
<p>其实Docker是C/S服务设计，所有的命令都是远程执行的~</p>
<p>还有COPY和ADD的指令。也只能获取当前目录里的内容，因为工作目录仅限于（上下文）目录 所以<code>COPY ../package.json /app</code> 或者 <code>COPY /opt/xxxx /app</code>不会成功工作</p>
<p><code>COPY ./package.json /app/</code></p>
<h2 id="5copy">5.COPY</h2>
<ul>
<li><code>COPY &lt;源路径&gt;... &lt;目标路径&gt;</code></li>
<li><code>COPY [&quot;&lt;源路径1&gt;&quot;,... &quot;&lt;目标路径&gt;&quot;]</code></li>
</ul>
<blockquote>
<p>此外，还需要注意一点，使用 COPY 指令，源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git进行管理的时候。</p>
</blockquote>
<p>在 Docker 官方的 Dockerfile 最佳实践文档 中要求，尽可能的使用 COPY ，因为 COPY 的语义很明确，就是复制文件而已，而 ADD 则包含了更复杂的功能，其行为也不一定很清晰。最适合使用 ADD 的场合，就是所提及的需要自动解压缩的场合。</p>
<h2 id="6-cmd-容器启动命令">6. CMD 容器启动命令</h2>
<ul>
<li>shell 格式： <code>CMD &lt;命令&gt;</code></li>
<li>exec 格式： <code>CMD [&quot;可执行文件&quot;, &quot;参数1&quot;, &quot;参数2&quot;...]</code></li>
<li>参数列表格式： <code>CMD [&quot;参数1&quot;, &quot;参数2&quot;...] 。在指定了 ENTRYPOINT 指令后，用 CMD 指定具体的参数。</code></li>
</ul>
<blockquote>
<h1 id="注意">注意</h1>
</blockquote>
<p>新手会在这里卡很长时间：刚开始的时候大家对Docker的理解仍然处于一种虚拟机的感觉，因此会使用那么<code>service</code>或者<code>systemctl</code>等命令去启动服务，然而<code>RUN</code> shell的操作方法会将命令转化为<code>CMD [&quot;sh&quot; , &quot;-c&quot;, &quot;你的命令&quot;]</code>如果执行，<code>sh</code>就作为主进程开始运行，并且尝试启动<code>systemctl</code>，但是容器里面根本没有这个东西，因此就结束了，sh也会结束，主进程结束了那么容器也就不存在了，不知道我是否表达清楚，这里贴上原作者的描述。</p>
<blockquote>
<p>而使用 <code>service nginx start</code> 命令，则是希望 <code>systemd</code> 来以后台守护进程形式启动 <code>nginx</code> 服务。而刚才说了 <code>CMD service nginx start</code> 会被理解为 <code>CMD [ “sh”, “-c”, “service nginxstart”]</code>，因此主进程实际上是 <code>sh</code> 。那么当 <code>service nginx start</code> 命令结束后， <code>sh</code> 也就结束了， <code>sh</code> 作为主进程退出了，自然就会令容器退出。</p>
</blockquote>
<h2 id="7-entrypoint-入口点">7. ENTRYPOINT 入口点</h2>
<p><code>ENTRYPOINT</code> 的格式和 <code>RUN</code> 指令格式一样，分为 <code>exec</code> 格式和 <code>shell</code> 格式。</p>
<blockquote>
<p>ENTRYPOINT 的目的和 CMD 一样，都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代，不过比 CMD 要略显繁琐，需要通过 docker run 的参数 –entrypoint 来指定。</p>
</blockquote>
<p>当指定了 ENTRYPOINT 后， CMD 的含义就发生了改变，不再是直接的运行其命令，而是将CMD 的内容作为参数传给 ENTRYPOINT 指令，换句话说实际执行时，将变为：</p>
<p><code>&lt;ENTRYPOINT&gt; &quot;&lt;CMD&gt;&quot;</code></p>
<h3 id="1像程序一样使用docker命令">1.像程序一样使用Docker命令</h3>
<p>当我们需要构建一个Docker来得到自己的公网镜像</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$cat Dockerfile
FROM ubuntu:16.04
RUN apt-get update <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span><span style="color:#f92672">&amp;&amp;</span> apt-get install -y curl <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span><span style="color:#f92672">&amp;&amp;</span> rm -rf /var/lib/apt/lists/*
CMD <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;curl&#34;</span>, <span style="color:#e6db74">&#34;-s&#34;</span>, <span style="color:#e6db74">&#34;http://ip.cn&#34;</span> <span style="color:#f92672">]</span>
</code></pre></div><p>运行的时候</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$docker build -t myip .
$docker run myip
当前 IP：61.148.226.66 来自：北京市 联通
</code></pre></div><p>嗯，这么看起来好像可以直接把镜像当做命令使用了，不过命令总有参数，如果我们希望加参数呢？比如从上面的 <code>CMD</code> 中可以看到实质的命令是 <code>curl</code> ，那么如果我们希望显示 <code>HTTP</code>头信息，就需要加上 <code>-i</code> 参数。那么我们可以直接加 <code>-i</code> 参数给 <code>docker run myip</code> 么？</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ docker run myip -i
docker: Error response from daemon: invalid header field value <span style="color:#e6db74">&#34;oci runtime error: con
</span><span style="color:#e6db74">tainer_linux.go:247: starting container process caused \&#34;exec: \\\&#34;-i\\\&#34;: executable
</span><span style="color:#e6db74">file not found in </span>$PATH<span style="color:#e6db74">\&#34;\n&#34;</span>.
</code></pre></div><p>你提前设定好的CMD就会被覆盖</p>
<p>要么我们得使用整个命令替代 <code>docker run myip curl -s http://ip.cn -i</code></p>
<p>这显然不是很好的解决方案，而使用 ENTRYPOINT 就可以解决这个问题。现在我们重新用 ENTRYPOINT 来实现这个镜像：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">FROM ubuntu:16.04
RUN apt-get update <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> apt-get install -y curl <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> rm -rf /var/lib/apt/lists/*
ENTRYPOINT <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;curl&#34;</span>, <span style="color:#e6db74">&#34;-s&#34;</span>, <span style="color:#e6db74">&#34;http://ip.cn&#34;</span> <span style="color:#f92672">]</span>
</code></pre></div><p>构建好了，使用附加命令 -i</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ docker run myip
当前 IP：61.148.226.66 来自：北京市 联通

$ docker run myip -i
HTTP/1.1 <span style="color:#ae81ff">200</span> OK
Server: nginx/1.8.0
Date: Tue, <span style="color:#ae81ff">22</span> Nov <span style="color:#ae81ff">2016</span> 05:12:40 GMT
Content-Type: text/html; charset<span style="color:#f92672">=</span>UTF-8
Vary: Accept-Encoding
X-Powered-By: PHP/5.6.24-1~dotdeb+7.1
X-Cache: MISS from cache-2
X-Cache-Lookup: MISS from cache-2:80
X-Cache: MISS from proxy-2_6
Transfer-Encoding: chunked
Via: 1.1 cache-2:80, 1.1 proxy-2_6:8006
Connection: keep-alive

当前 IP：61.148.226.66 来自：北京市 联通
</code></pre></div><p>可以看到，这次成功了。这是因为当存在 <code>ENTRYPOINT</code> 后， <code>CMD</code> 的内容将会作为参数传给 <code>ENTRYPOINT</code> ，而这里 <code>-i</code> 就是新的 <code>CMD</code> ，因此会作为参数传给 <code>curl</code> ，从而达到了我们预期的效果。</p>
<h3 id="2应用运行前的准备工作">2.应用运行前的准备工作</h3>
<p>启动容器就是启动主程序，但是在启动之前可能需要首先配置一下。</p>
<p>可以写一个脚本，然后放入 ENTRYPOINT 中去执行</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">FROM alpine:3.4
...
RUN addgroup -S redis <span style="color:#f92672">&amp;&amp;</span> adduser -S -G redis redis
...
ENTRYPOINT <span style="color:#f92672">[</span><span style="color:#e6db74">&#34;docker-entrypoint.sh&#34;</span><span style="color:#f92672">]</span>
EXPOSE <span style="color:#ae81ff">6379</span>
CMD <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;redis-server&#34;</span> <span style="color:#f92672">]</span>
</code></pre></div><p>写一个脚本，下面写了一个脚本，是根据CMD的内容来判断，如果是 redis-server 的话，则切换到 redis 用户身份启动服务器，否则依旧使用 root 身份执行。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e">#!/bin/sh
</span><span style="color:#75715e"></span>...
<span style="color:#75715e"># allow the container to be started with `--user`</span>
<span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$1<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;redis-server&#39;</span> -a <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>id -u<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;0&#39;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
    chown -R redis .
    exec su-exec redis <span style="color:#e6db74">&#34;</span>$0<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;</span>$@<span style="color:#e6db74">&#34;</span>
<span style="color:#66d9ef">fi</span>
exec <span style="color:#e6db74">&#34;</span>$@<span style="color:#e6db74">&#34;</span>
</code></pre></div><p>执行</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ docker run -it redis id
uid<span style="color:#f92672">=</span>0<span style="color:#f92672">(</span>root<span style="color:#f92672">)</span> gid<span style="color:#f92672">=</span>0<span style="color:#f92672">(</span>root<span style="color:#f92672">)</span> groups<span style="color:#f92672">=</span>0<span style="color:#f92672">(</span>root<span style="color:#f92672">)</span>
</code></pre></div><h2 id="8-env设置环境变量">8. ENV设置环境变量</h2>
<ul>
<li><code>ENV &lt;key&gt; &lt;value&gt;</code></li>
<li><code>ENV &lt;key1&gt;=&lt;value1&gt; &lt;key2&gt;=&lt;value2&gt;...</code></li>
</ul>
<pre><code>ENV VERSION=1.0 DEBUG=on \
    NAME=&quot;Happy Feet&quot;
</code></pre><p>定义了环境变量，那么在后续的指令中，就可以使用这个环境变量。比如在官方 node 镜像 Dockerfile 中，就有类似这样的代码：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">ENV NODE_VERSION 7.2.0
RUN curl -SLO <span style="color:#e6db74">&#34;https://nodejs.org/dist/v</span>$NODE_VERSION<span style="color:#e6db74">/node-v</span>$NODE_VERSION<span style="color:#e6db74">-linux-x64.ta
</span><span style="color:#e6db74">r.xz&#34;</span> <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> curl -SLO <span style="color:#e6db74">&#34;https://nodejs.org/dist/v</span>$NODE_VERSION<span style="color:#e6db74">/SHASUMS256.txt.asc&#34;</span> <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> grep <span style="color:#e6db74">&#34; node-v</span>$NODE_VERSION<span style="color:#e6db74">-linux-x64.tar.xz\$&#34;</span> SHASUMS256.txt | sha256sum -c - <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> tar -xJf <span style="color:#e6db74">&#34;node-v</span>$NODE_VERSION<span style="color:#e6db74">-linux-x64.tar.xz&#34;</span> -C /usr/local --strip-components<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span> <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> rm <span style="color:#e6db74">&#34;node-v</span>$NODE_VERSION<span style="color:#e6db74">-linux-x64.tar.xz&#34;</span> SHASUMS256.txt.asc SHASUMS256.txt <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span>    <span style="color:#f92672">&amp;&amp;</span> ln -s /usr/local/bin/node /usr/local/bin/nodejs
</code></pre></div><p>在这里先定义了环境变量 NODE_VERSION ，其后的 RUN 这层里，多次使用 $NODE_VERSION 来进行操作定制。可以看到，将来升级镜像构建版本的时候，只需要更新 7.2.0 即可， Dockerfile 构建维护变得更轻松了。</p>
<h2 id="8-volume匿名卷">8. Volume匿名卷</h2>
<h2 id="9-expose端口">9. EXPOSE端口</h2>
<p><code>EXPOSE</code> 指令是声明运行时容器提供服务端口，这只是一个声明，在运行时并不会因为这个声明应用就会开启这个端口的服务</p>
<h2 id="10-user-指定当前用户">10. USER 指定当前用户</h2>
<pre><code>RUN groupadd -r redis &amp;&amp; useradd -r -g redis redis
USER redis
RUN [ &quot;redis-server&quot; ]
</code></pre><h2 id="10-还有使用git-repo-和tar压缩包构建的指令">10. 还有使用Git repo 和tar压缩包构建的指令</h2>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.14

$ docker build http://server/context.tar.gz
</code></pre></div>
    </article>
</div>


        
<nav role="navigation" class="flex-container bottom-menu">
    
<hr />
<p>


    
        <a href="/posts">back</a>
        
            &#183;
        
    

    
        
            <a href="/posts">我的文章</a>
        
    
    
        
            &#183; 
            <a href="/gallery">画册</a>
        
            &#183; 
            <a href="/portfolio">珍贵时光</a>
        
            &#183; 
            <a href="/about">关于我</a>
        
    
    &#183; 
    <a href="/">
        main
    </a>

</p>
</nav>

    </main>
    
    <footer class="flex-container footer">I will code for a long time. Would you?</footer>
    
    
</body>

</html>